package org.road0329.tools.proto_parse_tool.utils;

import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ProtocolUtils {

    private static Pattern pattern = Pattern.compile("^[-+]?(([0-9]+)([.]([0-9]+))?|([.]([0-9]+))?)$");

    public static String printMsg(int from, int to, byte[] sendData) {
        if (sendData == null || sendData.length <= from || sendData.length < to) {
            return "";
        }
        StringBuffer res = new StringBuffer("");
        if (to > from) {
            for (int i = (int) from; i < to; i++) {
                String temp = Integer.toHexString(0xFF & sendData[i]).toUpperCase();
                if (temp.length() == 1) {
                    res.append("0" + temp + " ");
                } else {
                    res.append(temp + " ");
                }
            }
        } else {

            for (int i = (int) from; i < sendData.length + to; i++) {
                String temp = Integer.toHexString(0xFF & sendData[i % sendData.length]).toUpperCase();
                if (temp.length() == 1) {
                    res.append("0" + temp + " ");
                } else {
                    res.append(temp + " ");
                }
            }
        }
        return res.toString();

    }

    public static String DLMSLNFormat(String ln) {
        String temp = ln.replace("-", ",");
        temp = temp.replace(":", ",");
        temp = temp.replace(".", ",");
        temp = temp.replace("{", "");
        temp = temp.replace("}", "");
        return temp;
    }

    public static int Unsignd(byte b) {
        return 0xff & b;
    }

    public static long Unsigndlong(byte b) {
        return 0xff & b;
    }

    /**
     * @param hex 10进制数字的二进制表示
     * @return 10进制数字的BCD码
     */
    public static byte HexToBCD(byte hex) {
        return (byte) (hex / 10 * 0x10 + hex % 10);
    }

    /**
     * @param bcd 10进制数字的BCD码
     * @return 10进制数字的二进制表示
     */
    public static byte BCDToHex(byte bcd) {
        return (byte) ((bcd & 0x0F) + ((bcd >> 4) & 0x0F) * 10);
    }

    /**
     * 一组BCD码合成 从offset开始，len 个字符,函数内不检查越界错误
     *
     * @param bcd    数组
     * @param offset 数组起始字符 offset>=0 && offset<bcd.length
     * @param len    转化字节个数,len > 0 &&len <min(5,bcd.length-offset)
     * @param desc   顺序， desc=true时 低字节在前，高字节在后;desc=false 高字节在前，低字节在后
     * @return
     */
    public static int BCDsToInt(byte bcd[], int offset, int len, boolean desc) {
        int res = 0;
        if (desc) {
            for (int i = len - 1; i >= 0; i--) {
                res = res * 100 + BCDToHex(bcd[offset + i]);
            }
        } else {
            for (int i = 0; i < len; i++) {
                res = res * 100 + (bcd[offset + i]);
            }
        }
        return res;
    }

    /**
     * 和校验
     *
     * @param data 校验源，byte数组
     * @param from 校验开始字节序号
     * @param num  校验字节数
     * @return 返回和，高位清零
     */
    public static byte CheckSum(byte[] data, int from, int num) {
        int sum = 0;
        for (int i = from; i < from + num; i++) {
            sum += Unsignd(data[i]);
        }
        return (byte) (sum & 0xff);
    }

    /**
     * 异或运算
     *
     * @param data 校验源，byte数组
     * @param from 校验开始字节序号
     * @param num  校验字节数
     * @return 返回和，高位清零
     */
    public static byte CheckXor(byte[] data, int from, int num) {
        int sum = 0;
        for (int i = from; i < from + num; i++) {
            sum = sum ^ Unsignd(data[i]);
        }
        return (byte) (sum & 0xff);
    }

    /**
     * 把 byte 数组以16进制格式输出到字符串里，便于打印,输出格式样子为:<br>
     * 68 01 01 68 E1 F1
     *
     * @param byteValue
     * @param len
     * @return
     */
    public static String getByteToHexString(byte[] byteValue, int off, int len, String token) {
        if (byteValue == null)
            return "";
        StringBuilder res = new StringBuilder();
        for (int i = off; i < off + len; i++) {
            String temp = Integer.toHexString(0xFF & byteValue[i]).toUpperCase();
            if (temp.length() == 1) {
                res.append("0").append(temp).append(token);
            } else {
                res.append(temp).append(token);
            }

        }
        return res.toString();
    }

    public static String getByteToHexStringDesc(byte[] byteValue, int len, String token) {
        if (byteValue == null)
            return "";
        StringBuilder res = new StringBuilder();
        int count = Math.min(len, byteValue.length);
        for (int i = count - 1; i >= 0; i--) {
            String temp = Integer.toHexString(0xFF & byteValue[i]).toUpperCase();
            if (temp.length() == 1) {
                res.append("0").append(temp).append(token);
            } else {
                res.append(temp).append(token);
            }
        }
        return res.toString();
    }

    public static String getByteToHexStringDesc(byte[] byteValue, int from, int len, String token) {
        if (byteValue == null)
            return "";
        StringBuilder res = new StringBuilder();
        int count = Math.min(len, byteValue.length - from);
        for (int i = count - 1; i >= 0; i--) {
            String temp = Integer.toHexString(0xFF & byteValue[i + from]).toUpperCase();
            if (temp.length() == 1) {
                res.append("0").append(temp).append(token);
            } else {
                res.append(temp).append(token);
            }
        }
        return res.toString();
    }

    public static void main(String[] args) {
//        String message = "A0 DE 14 0A 94 06 13";
//        message = message.replaceAll(" ","");
//        message = ProtocolUtils.reverse(message, message.length());
//        byte[] bytes = ProtocolUtils.StringToHex(message);
//        System.out.print(getDateByCP56Time2a(bytes));
        // byte[] dd = StringToHex("0x12");

//        String message = "00 D5";
//        byte[] buf = message2Bytes(message);
//        System.out.println(byteToFloat(buf[1], buf[0],1));

//        byte[] buf = message2Bytes("58 98 20 0D 11 07 13 ");
//        System.out.println(getDateByCP56Time2a(buf));

//        String message = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 43 00 00 05 99 00 07 00 11 22 33 02 00 10";
//        message = message.replaceAll(" ","");
//        byte[] buf =ProtocolUtils.StringToHex(message);

/*        String message ="44DB6000";
        byte[] buf = message2Bytes(message);

        System.out.println(byte2IEEE754Float(buf));

        float  value=Float.intBitsToFloat(Integer.valueOf(message, 16));
        System.out.println(value);*/
        System.out.println(new BigDecimal("2.81"));
        System.out.println((float)Math.round(2.8099999427795410*10000)/10000);


    }

    /**
     * 固定长度的转化，超过取低位，少了高位补0
     *
     * @param str
     * @param len 转化为byte后的字节数
     * @return
     */
    public static byte[] StringToHex(String str, int len) {
        if (str == null || str.length() == 0)
            return null;
        if (str.length() > (2 * len)) {
            return StringToHex(str.substring(str.length() - 2 * len));
        } else if (str.length() == (2 * len)) {
            return StringToHex(str);
        } else {
            for (int i = len * 2 - str.length(); i > 0; i--) {
                str = "0" + str;
            }
            return StringToHex(str);
        }

    }

    /**
     * String 转化为 byte
     *
     * @param str,必须为16进制字符 0~9,A~F，其他字符将被用0替代
     * @return
     */
    public static byte[] StringToHex(String str) {
        str = str.trim();
        if (str == null || str.length() == 0)
            return null;
        if (str.length() == 1) {
            str = "0" + str;
        }
        String newStr = str.replaceAll("[^0-9A-Fa-f]", "0");
        if (newStr == null || newStr.length() == 0)
            return null;
        if (newStr.length() % 2 == 1) {
            newStr = "0" + newStr;
        }
        int len = newStr.length() / 2;

        byte[] res = new byte[len];
        for (int i = 0; i < len; i++) {
            String t = newStr.substring(newStr.length() - 2 * (i + 1), newStr.length() - 2 * i);
            res[i] = (byte) (Integer.parseInt(t, 16) % 0x100);
        }
        return res;
    }

    // 正向转换
    public static byte[] StringToHexAsc(String str) {
        str = str.trim();
        if (str == null || str.length() == 0)
            return null;
        if (str.length() == 1) {
            str = "0" + str;
        }
        String newStr = str.replaceAll("[^0-9A-Fa-f]", "0");
        if (newStr == null || newStr.length() == 0)
            return null;
        if (newStr.length() % 2 == 1) {
            newStr = "0" + newStr;
        }
        int len = newStr.length() / 2;

        byte[] res = new byte[len];
        for (int i = 0; i < len; i++) {
            String t = newStr.substring(i * 2, (i + 1) * 2);
            res[i] = (byte) (Integer.parseInt(t, 16) % 0x100);
        }
        return res;
    }

    public static byte[] logicNameCovert(String name) {
        String[] items = ((String) name).split("[.]", -1);
        byte[] byteName = new byte[6];
        if (items.length != 6) {
            return new byte[]{0, 0, 0, 0, 0, 0};
        }
        int i = 0;
        for (String it : items) {
            byteName[i++] = (byte) (Short.parseShort(it) & 0xFF);
        }
        return byteName;
    }

    public static String reverse(String src, int len) {
        if (src.length() % 2 == 1)
            src = "0" + src;
        src = StringUtil.AddjustLength(src, len, "0");
        int arrLen = len / 2;
        String[] pwdArray = new String[arrLen];

        for (int i = 0; i < len / 2; i++) {
            pwdArray[i] = src.substring(i * 2, (i + 1) * 2);
        }
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < arrLen; i++) {
            buf.append(pwdArray[arrLen - i - 1]);
        }
        return buf.toString();
    }

    /**
     * 6字节BCD码转化为时间字符串 YYYY-MM-DD mm:hh:00
     *
     * @param data
     * @param from
     * @param len
     * @return
     */
    public static String getStringDateByBCD(byte[] data, int from, int len) {
        if (data == null || data.length < (from + len)) {
            return null;
        }
        String dateStr = null;
        if (len == 5) {
            dateStr = String.format("20%02x-%02X-%02X %02X:%02X:00", data[4 + from], data[3 + from], data[2 + from],
                    data[1 + from], data[from]);
        } else if (len == 6) {
            dateStr = String.format("%02x%02x-%02X-%02X %02X:%02X:00", data[5 + from], data[4 + from], data[3 + from],
                    data[2 + from], data[1 + from], data[from]);
        }
        return dateStr;
    }

    public static String getStringByBCD(byte[] data, int from, int len) {
        if (data == null || data.length < (from + len)) {
            return null;
        }
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < len; i++) {
            builder.append(String.format("%02X", data[from + i]));
        }
        return builder.toString();
    }

    /**
     * 6字节BCD码转化为时间字符串 YY-MM-DD mm:hh:ss
     *
     * @param data
     * @param from
     * @param len
     * @return
     */
    public static String getStringDateByYYMMDDmmhhss(byte[] data, int from, int len) {
        if (data == null || data.length < (from + len)) {
            return null;
        }
        String dateStr = null;
        if (len == 5) {
            dateStr = String.format("20%02x-%02X-%02X %02X:%02X:00", data[4 + from], data[3 + from], data[2 + from],
                    data[1 + from], data[from]);
        } else if (len == 6) {
            dateStr = String.format("20%02x-%02X-%02X %02X:%02X:%02X", data[5 + from], data[4 + from], data[3 + from],
                    data[2 + from], data[1 + from], data[from]);
        }
        return dateStr;
    }

    public static byte[] getBCDDateByDate(Date beginTime) {
        byte[] data = new byte[7];
        Calendar d = Calendar.getInstance();
        d.setTime(beginTime);
        data[0] = HexToBCD((byte) d.get(Calendar.SECOND));
        data[1] = HexToBCD((byte) d.get(Calendar.MINUTE));
        data[2] = HexToBCD((byte) d.get(Calendar.HOUR_OF_DAY));
        data[3] = HexToBCD((byte) d.get(Calendar.DAY_OF_MONTH));
        data[4] = HexToBCD((byte) (d.get(Calendar.MONTH) + 1));
        data[5] = HexToBCD((byte) (d.get(Calendar.YEAR) % 100));
        data[6] = HexToBCD((byte) (d.get(Calendar.YEAR) / 100));
        return data;
    }

    public static String strReverse(String itemChar) {
        if (itemChar == null) {
            return null;
        }
        String temp = "";
        for (int i = itemChar.length() - 1; i >= 1; i = i - 2) {
            temp += String.valueOf(itemChar.charAt(i - 1)) + String.valueOf(itemChar.charAt(i));
        }
        return temp;
    }

    public static String dataToString(Object data) {
        if (data == null) {
            return "";
        }
        if (data instanceof byte[]) {
            byte[] bytes = (byte[]) data;

            return ProtocolUtils.getByteToHexString(bytes, 0, bytes.length, " ");
        }
        return String.valueOf(data);
    }

    public static byte[] replaceDirtyByte(byte[] data) {
        byte[] result = new byte[data.length];
        for (int i = 0; i < data.length; i++) {
            if (data[i] == 0) {
                result[i] = 32;
            } else {
                result[i] = data[i];
            }
        }
        return result;
    }

    public static byte lowByte(short value) {
        return (byte) (value & 0xFF);
    }

    public static byte highByte(short value) {
        return (byte) ((value >> 8) & 0xFF);
    }

    public static float byteToFloat(byte high, byte low, int scale) {
        short num = byteToShort(high, low);

        return valueToDecimal(num, scale).floatValue();
    }

    public static short byteToShort(byte high, byte low) {
        short res = (short) (ProtocolUtils.Unsignd(high) * 0x100 + ProtocolUtils.Unsignd(low));
        return res;
    }

    /**
     * 有符号数，两个字节，高位符号位
     *
     * @param high
     * @param low
     * @return
     */
    public static int byteToSignInt(byte high, byte low) {
        int sign = high & 0x80;
        high = (byte) (high & 0x7F);
        int res = (int) (ProtocolUtils.Unsignd(high) * 0x100 + ProtocolUtils.Unsignd(low));
        if (sign != 0) {
            res = -res;
        }
        return res;
    }

    public static float byteToSignFloat(byte high, byte low, int scale) {
        int value = byteToSignInt(high, low);

        return valueToDecimal(value, scale).floatValue();
    }

    public static void copyBytes(byte[] buf, byte[] resbuf, int len) {
        if (buf == null || resbuf == null) {
            return;
        }
        for (int i = 0; i < len; i++) {
            if (i >= buf.length || i >= resbuf.length) {
                return;
            }
            resbuf[i] = buf[i];
        }

    }

    public static void copyBytes(byte[] buf, int from1, byte[] resbuf, int from2, int len) {
        if (buf == null || resbuf == null) {
            return;
        }
        for (int i = 0; i < len; i++) {
            if (i + from1 >= buf.length || i + from2 >= resbuf.length) {
                return;
            }
            resbuf[i + from2] = buf[i + from1];
        }

    }

    public static int byteTolongShort(byte high, byte low) {
        int res = (int) (ProtocolUtils.Unsignd(high) * 0x100 + ProtocolUtils.Unsignd(low));
        return res;
    }

    public static int threeByteToInteger(byte high, byte mid, byte low) {
        int res = (ProtocolUtils.Unsignd(high) * 0x10000+ ProtocolUtils.Unsignd(mid) * 0x100 + ProtocolUtils.Unsignd(low));
        return res;
    }

    public static int byteToInteger(byte[] data, int from) {
        if (data == null || data.length < 4 + from) {
            return 0;
        }
        return (ProtocolUtils.Unsignd(data[from + 3]) * 0x1000000
                + ProtocolUtils.Unsignd(data[from + 2]) * 0x10000 + ProtocolUtils.Unsignd(data[from + 1]) * 0x100
                + ProtocolUtils.Unsignd(data[from]));
    }

    public static long byteToLong(byte[] data, int from) {
        if (data == null || data.length < 8 + from) {
            return 0;
        }
        long result=0;
        long factor=1;
        for(int i=0;i<8;i++){
            result+=ProtocolUtils.Unsignd(data[from+i])*factor;
            factor=factor<<8;
        }
        return result;
    }

    //小端
    public static float byteToFloat(byte[] data,int from) {
        if (data == null || data.length < 4 + from) {
            return 0;
        }
        byte[] copy = new byte[4];
        System.arraycopy(data, from, copy, 0, 4);
        ByteBuffer buf= ByteBuffer.allocateDirect(4); //无额外内存的直接缓存
        buf=buf.order(ByteOrder.LITTLE_ENDIAN);//默认大端(高地址在前)，小端用这行
        buf.put(copy);
        buf.rewind();
        return (float)Math.round(buf.getFloat()*10000)/10000; //默认浮点型保留四位小数
    }

    //小端
    public static double byteToDouble(byte[] data,int from) {
        if (data == null || data.length < 8 + from) {
            return 0;
        }
        byte[] copy = new byte[8];
        System.arraycopy(data, from, copy, 0, 8);
        ByteBuffer buf= ByteBuffer.allocateDirect(8); //无额外内存的直接缓存
        buf=buf.order(ByteOrder.LITTLE_ENDIAN);//默认大端(高地址在前)，小端用这行
        buf.put(copy);
        buf.rewind();
        return (double)Math.round(buf.getDouble()*10000)/10000; //默认浮点型保留四位小数
    }

    public static BigDecimal byteToBigDecimal(byte[] data, int from, int len, int scale) {
        if (len == 4) {
            long num = byteToInteger(data, from);
            return valueToDecimal(num, scale);
        } else if (len == 2) {
            long num = byteTolongShort(data[from], data[from++]);
            return valueToDecimal(num, scale);
        } else {
            //logger.warn("not support length = " + len);
        }
        return null;
    }

    public static double byteToDouble(byte[] data, int from, int scale) {
        return byteToBigDecimal(data, from, 4, scale).doubleValue();
    }

    public static BigDecimal valueToDecimal(short value, int scale) {
        BigDecimal decimal = BigDecimal.valueOf(value);
        return decimal.divide(BigDecimal.valueOf(Math.pow(10, scale)), scale, BigDecimal.ROUND_HALF_UP);
    }

    public static BigDecimal valueToDecimal(int value, int scale) {
        BigDecimal decimal = BigDecimal.valueOf(value);
        return decimal.divide(BigDecimal.valueOf(Math.pow(10, scale)), scale, BigDecimal.ROUND_HALF_UP);
    }

    public static BigDecimal valueToDecimal(long value, int scale) {
        BigDecimal decimal = BigDecimal.valueOf(value);
        return decimal.divide(BigDecimal.valueOf(Math.pow(10, scale)), scale, BigDecimal.ROUND_HALF_UP);
    }

    public static Integer BinToInteger(char[] src) {
        long n = 0;
        for (int k = src.length - 1; k >= 0; k--) {
            if (src[k] == '1') {
                n = (int) (n + Math.pow(2, src.length - 1 - k));
            }
        }
        return (int) n;
    }

    public static float byte2IEEE754Float(byte[] value) {
        String message = bytesToHexString(value);
        return Float.intBitsToFloat(Integer.valueOf(message, 16));
    }

    public static String hex2Bin(byte src) {
        String result = new String();
        for (int i = 0; i < 8; i++) {
            if ((src & 0x01) == 1) {
                result = "1" + result;
            } else {
                result = "0" + result;
            }
            src >>= 1;
        }
        return result.toString();
    }

    public static float byte2int_Float(byte b[], int index) {
        int bits = b[index + 3] & 0xff | (b[index + 2] & 0xff) << 8 | (b[index + 1] & 0xff) << 16
                | (b[index] & 0xff) << 24;

        int sign = ((bits & 0x80000000) == 0) ? 1 : -1;
        long exponent = ((bits & 0x7f800000) >> 23);
        int mantissa = (bits & 0x007fffff);

        mantissa |= 0x00800000;
        // Calculate the result:
        float f = (float) (sign * mantissa * Math.pow(2, exponent - 150));
        return f;
    }

    public static Date adjustTimeBySampleInterval(Calendar now, String sampleinterval) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(now.getTime());
        if (sampleinterval == null) {
            return cal.getTime();
        }
        String type = sampleinterval.substring(0, 2);
        int num = 0;
        try {
            num = Integer.parseInt(sampleinterval.substring(2));
        } catch (Exception e) {
            return cal.getTime();
        }
        cal.set(Calendar.MILLISECOND, 0);
        cal.set(Calendar.SECOND, 0);

        if ("MI".equalsIgnoreCase(type)) {
            num %= 60;
            cal.set(Calendar.MINUTE, now.get(Calendar.MINUTE) / num * num);
        } else if ("HH".equalsIgnoreCase(type)) {
            num %= 24;
            cal.set(Calendar.MINUTE, 0);
            cal.set(Calendar.HOUR, now.get(Calendar.HOUR) / num * num);
        } else if ("DD".equalsIgnoreCase(type)) {
            num %= 31;
            cal.set(Calendar.MINUTE, 0);
            cal.set(Calendar.HOUR, 0);
            cal.set(Calendar.DAY_OF_MONTH, now.get(Calendar.DAY_OF_MONTH) / num * num + 1);
        } else if ("MM".equalsIgnoreCase(type)) {
            num %= 12;
            cal.set(Calendar.MINUTE, 0);
            cal.set(Calendar.HOUR, 0);
            cal.set(Calendar.DAY_OF_MONTH, 1);
            cal.set(Calendar.MONTH, now.get(Calendar.MONTH) / num * num);
        }

        return cal.getTime();
    }

    public static boolean isNum(String str) {
        Matcher isNum = pattern.matcher(str);
        if (!isNum.matches()) {
            return false;
        }
        return true;
    }

    public static byte[] stringToAscii(String str, int len) {
        byte[] res = new byte[len];
        char c;
        int i, j;
        if (str == null || str.isEmpty()) {
            return res;
        }
        try {
            byte[] temp = str.getBytes("US-ASCII");
            System.arraycopy(temp, 0, res, 0, Math.min(len, temp.length));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } finally {
            return res;
        }
    }

    public static String ascii2String(byte[] data, int from, int len) {

        String result = "";
        if (data != null) {
            try {
                byte[] b = new byte[len];
                System.arraycopy(data, from, b, 0, len);
                result = new String(b, "ascii");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    public static byte[] makeFrameSub33(byte[] byteValue, int index, int len) {
        byte[] newbytes = new byte[len];
        for (int i = 0; i < len; i++) {
            newbytes[i] = (byte) (byteValue[index + i] - 0x33);
        }
        return newbytes;
    }

    public static byte[] makeFrameAdd33(byte[] byteValue, int index, int len) {
        byte[] newbytes = new byte[len];
        for (int i = 0; i < len; i++) {
            newbytes[i] = (byte) (byteValue[index + i] + 0x33);
        }
        return newbytes;
    }

    /**
     * Convert byte[] to hex
     * string.这里我们可以将byte转换成int，然后利用Integer.toHexString(int)来转换成16进制字符串。
     *
     * @param src byte[] data
     * @return hex string
     */
    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * 将int转为低字节在前，高字节在后的byte数组
     */
    public static byte[] int2LowHigh(int n) {
        byte[] b = new byte[4];
        b[0] = (byte) (n & 0xff);
        b[1] = (byte) (n >> 8 & 0xff);
        b[2] = (byte) (n >> 16 & 0xff);
        b[3] = (byte) (n >> 24 & 0xff);
        return b;
    }

    /**
     * 将int转为高字节在前，低字节在后的byte数组
     */
    public static byte[] int2HighLow(int n) {
        byte[] b = new byte[4];
        b[3] = (byte) (n & 0xff);
        b[2] = (byte) (n >> 8 & 0xff);
        b[1] = (byte) (n >> 16 & 0xff);
        b[0] = (byte) (n >> 24 & 0xff);
        return b;
    }

    /**
     * 将short转为低字节在前，高字节在后的byte数组
     */
    public static byte[] short2LowHigh(int n) {
        byte[] b = new byte[2];
        b[0] = (byte) (n & 0xff);
        b[1] = (byte) (n >> 8 & 0xff);
        return b;
    }

    /**
     * 将short转为高字节在前，低字节在后的byte数组
     */
    public static byte[] short2HighLow(int n) {
        byte[] b = new byte[2];
        b[1] = (byte) (n & 0xff);
        b[0] = (byte) (n >> 8 & 0xff);
        return b;
    }

    /**
     * 将int转为低字节在前，高字节在后的byte数组
     */
    public static byte[] long2LowHigh(long n) {
        byte[] b = new byte[8];
        b[0] = (byte) (n & 0xff);
        b[1] = (byte) (n >> 8 & 0xff);
        b[2] = (byte) (n >> 16 & 0xff);
        b[3] = (byte) (n >> 24 & 0xff);
        b[4] = (byte) (n >> 32 & 0xff);
        b[5] = (byte) (n >> 40 & 0xff);
        b[6] = (byte) (n >> 48 & 0xff);
        b[7] = (byte) (n >> 56 & 0xff);
        return b;
    }

    /**
     * 将int转为高字节在前，低字节在后的byte数组
     */
    public static byte[] long2HighLow(long n) {
        byte[] b = new byte[8];
        b[7] = (byte) (n & 0xff);
        b[6] = (byte) (n >> 8 & 0xff);
        b[5] = (byte) (n >> 16 & 0xff);
        b[4] = (byte) (n >> 24 & 0xff);
        b[3] = (byte) (n >> 32 & 0xff);
        b[2] = (byte) (n >> 40 & 0xff);
        b[1] = (byte) (n >> 48 & 0xff);
        b[0] = (byte) (n >> 56 & 0xff);
        return b;
    }

    /**
     * 时标CP56Time2a解析
     *
     * @param b 时标CP56Time2a（长度为7 的int数组）
     * @return 解析结果
     */
    public static String getStringDateByCP56Time2a(byte[] b) {
        if (b == null || b.length < 7) {
            return null;
        }

        StringBuilder result = new StringBuilder();

        int year = b[6] & 0x7F;
        int month = b[5] & 0x0F;
        int day = b[4] & 0x1F;
        int week = (b[4] & 0xE0) / 32;
        int hour = b[3] & 0x1F;
        int minute = b[2] & 0x3F;
        int second = (b[1] << 8) + b[0];
        result.append(year + 2000).append("-");
        result.append(String.format("%02d", month)).append("-");
        result.append(String.format("%02d", day)).append(" ");
        result.append(hour).append(":").append(minute).append(":");
        result.append(second / 1000).append(".");
        result.append(String.format("%03d", second % 1000));

        return result.toString();
    }

    /**
     * 时标CP56Time2a解析
     *
     * @param b 时标CP56Time2a（长度为7 的int数组）
     * @return 解析结果
     */
    public static Date getDateByCP56Time2a(byte[] b) {
        String date = getStringDateByCP56Time2a(b);
        if (StringUtil.isEmpty(date)) {
            return null;
        }

        return DateUtil.StrToDate(date, DateUtil.TIME_TOO_LONG);
    }

    /**
     * 时标CP56Time2az组装
     *
     * @param dateTime 时间
     * @return 时标CP56Time2a（长度为7 的int数组）
     */
    public static byte[] getBytesByCP56Time2a(Date dateTime) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(dateTime);

        byte[] result = new byte[7];
        long milliSecond = (calendar.get(Calendar.SECOND) * 1000) + calendar.get(Calendar.MILLISECOND);
        result[0] = (byte) ((milliSecond & 0x00ff) & 0xff);
        result[1] = (byte) (((milliSecond & 0xff00) >> 8) & 0xff);
        result[2] = (byte) ((calendar.get(Calendar.MINUTE) & 0x3F) & 0xff);
        result[3] = (byte) ((calendar.get(Calendar.HOUR_OF_DAY) & 0x1F) & 0xff);

        int week = calendar.get(Calendar.DAY_OF_WEEK);
        if (week == Calendar.SUNDAY)
            week = 7;
        else week--;
        result[4] = (byte) (((week << 5) + (calendar.get(Calendar.DAY_OF_MONTH) & 0x1F)) & 0xff);
        result[5] = (byte) ((calendar.get(Calendar.MONTH) + 1) & 0xff);
        result[6] = (byte) ((calendar.get(Calendar.YEAR) - 2000) & 0xff);

        return result;
    }

    /**
     * 压缩BCD码 String -> byte[]
     *
     * @param s
     * @return
     */
    public static byte[] str2cbcd(String s) {
        if (s.length() % 2 != 0) {
            s = "0" + s;
        }
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        char[] cs = s.toCharArray();
        for (int i = 0; i < cs.length; i += 2) {
            int high = cs[i] - 48;
            int low = cs[i + 1] - 48;
            baos.write(high << 4 | low);
        }
        return baos.toByteArray();
    }

    /**
     * 压缩BCD码  byte[] ->String
     *
     * @param
     * @return
     */
    public static String cbcd2string(byte[] b) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
            int h = ((b[i] & 0xff) >> 4) + 48;
            sb.append((char) h);
            int l = (b[i] & 0x0f) + 48;
            sb.append((char) l);
        }
        return sb.toString();
    }

    /**
     * BCD字串转16进制 字节码
     *
     * @param val
     * @param length
     * @return
     */
    public static byte[] bcdString2Hex(String val, int length) {
        String value = StringUtil.AddjustLength(val, length * 2, "00");
        byte temp;
        byte[] result = new byte[length];
        for (int i = 0; i < length; i++) {
            temp = (byte) Integer.parseInt(value.substring(2 * i, 2 * i + 2), 16);
            result[length - 1 - i] = ProtocolUtils.BCDToHex(temp);
        }
        return result;
    }

    /**
     * 报文字串 转 字节数组
     *
     * @param message
     * @return
     */
    public static byte[] message2Bytes(String message) {
        if (StringUtil.isEmpty(message)) {
            return new byte[0];
        }
        message = message.replaceAll(" ", "");
        message = ProtocolUtils.reverse(message, message.length());
        return ProtocolUtils.StringToHex(message);
    }
    /**
     * 查表法计算CRC16校验
     *
     * @param data 需要计算的字节数组
     */
    public static String getCRC3(byte[] data) {
        byte[] crc16_h = {
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40
        };

        byte[] crc16_l = {
                (byte) 0x00, (byte) 0xC0, (byte) 0xC1, (byte) 0x01, (byte) 0xC3, (byte) 0x03, (byte) 0x02, (byte) 0xC2, (byte) 0xC6, (byte) 0x06, (byte) 0x07, (byte) 0xC7, (byte) 0x05, (byte) 0xC5, (byte) 0xC4, (byte) 0x04,
                (byte) 0xCC, (byte) 0x0C, (byte) 0x0D, (byte) 0xCD, (byte) 0x0F, (byte) 0xCF, (byte) 0xCE, (byte) 0x0E, (byte) 0x0A, (byte) 0xCA, (byte) 0xCB, (byte) 0x0B, (byte) 0xC9, (byte) 0x09, (byte) 0x08, (byte) 0xC8,
                (byte) 0xD8, (byte) 0x18, (byte) 0x19, (byte) 0xD9, (byte) 0x1B, (byte) 0xDB, (byte) 0xDA, (byte) 0x1A, (byte) 0x1E, (byte) 0xDE, (byte) 0xDF, (byte) 0x1F, (byte) 0xDD, (byte) 0x1D, (byte) 0x1C, (byte) 0xDC,
                (byte) 0x14, (byte) 0xD4, (byte) 0xD5, (byte) 0x15, (byte) 0xD7, (byte) 0x17, (byte) 0x16, (byte) 0xD6, (byte) 0xD2, (byte) 0x12, (byte) 0x13, (byte) 0xD3, (byte) 0x11, (byte) 0xD1, (byte) 0xD0, (byte) 0x10,
                (byte) 0xF0, (byte) 0x30, (byte) 0x31, (byte) 0xF1, (byte) 0x33, (byte) 0xF3, (byte) 0xF2, (byte) 0x32, (byte) 0x36, (byte) 0xF6, (byte) 0xF7, (byte) 0x37, (byte) 0xF5, (byte) 0x35, (byte) 0x34, (byte) 0xF4,
                (byte) 0x3C, (byte) 0xFC, (byte) 0xFD, (byte) 0x3D, (byte) 0xFF, (byte) 0x3F, (byte) 0x3E, (byte) 0xFE, (byte) 0xFA, (byte) 0x3A, (byte) 0x3B, (byte) 0xFB, (byte) 0x39, (byte) 0xF9, (byte) 0xF8, (byte) 0x38,
                (byte) 0x28, (byte) 0xE8, (byte) 0xE9, (byte) 0x29, (byte) 0xEB, (byte) 0x2B, (byte) 0x2A, (byte) 0xEA, (byte) 0xEE, (byte) 0x2E, (byte) 0x2F, (byte) 0xEF, (byte) 0x2D, (byte) 0xED, (byte) 0xEC, (byte) 0x2C,
                (byte) 0xE4, (byte) 0x24, (byte) 0x25, (byte) 0xE5, (byte) 0x27, (byte) 0xE7, (byte) 0xE6, (byte) 0x26, (byte) 0x22, (byte) 0xE2, (byte) 0xE3, (byte) 0x23, (byte) 0xE1, (byte) 0x21, (byte) 0x20, (byte) 0xE0,
                (byte) 0xA0, (byte) 0x60, (byte) 0x61, (byte) 0xA1, (byte) 0x63, (byte) 0xA3, (byte) 0xA2, (byte) 0x62, (byte) 0x66, (byte) 0xA6, (byte) 0xA7, (byte) 0x67, (byte) 0xA5, (byte) 0x65, (byte) 0x64, (byte) 0xA4,
                (byte) 0x6C, (byte) 0xAC, (byte) 0xAD, (byte) 0x6D, (byte) 0xAF, (byte) 0x6F, (byte) 0x6E, (byte) 0xAE, (byte) 0xAA, (byte) 0x6A, (byte) 0x6B, (byte) 0xAB, (byte) 0x69, (byte) 0xA9, (byte) 0xA8, (byte) 0x68,
                (byte) 0x78, (byte) 0xB8, (byte) 0xB9, (byte) 0x79, (byte) 0xBB, (byte) 0x7B, (byte) 0x7A, (byte) 0xBA, (byte) 0xBE, (byte) 0x7E, (byte) 0x7F, (byte) 0xBF, (byte) 0x7D, (byte) 0xBD, (byte) 0xBC, (byte) 0x7C,
                (byte) 0xB4, (byte) 0x74, (byte) 0x75, (byte) 0xB5, (byte) 0x77, (byte) 0xB7, (byte) 0xB6, (byte) 0x76, (byte) 0x72, (byte) 0xB2, (byte) 0xB3, (byte) 0x73, (byte) 0xB1, (byte) 0x71, (byte) 0x70, (byte) 0xB0,
                (byte) 0x50, (byte) 0x90, (byte) 0x91, (byte) 0x51, (byte) 0x93, (byte) 0x53, (byte) 0x52, (byte) 0x92, (byte) 0x96, (byte) 0x56, (byte) 0x57, (byte) 0x97, (byte) 0x55, (byte) 0x95, (byte) 0x94, (byte) 0x54,
                (byte) 0x9C, (byte) 0x5C, (byte) 0x5D, (byte) 0x9D, (byte) 0x5F, (byte) 0x9F, (byte) 0x9E, (byte) 0x5E, (byte) 0x5A, (byte) 0x9A, (byte) 0x9B, (byte) 0x5B, (byte) 0x99, (byte) 0x59, (byte) 0x58, (byte) 0x98,
                (byte) 0x88, (byte) 0x48, (byte) 0x49, (byte) 0x89, (byte) 0x4B, (byte) 0x8B, (byte) 0x8A, (byte) 0x4A, (byte) 0x4E, (byte) 0x8E, (byte) 0x8F, (byte) 0x4F, (byte) 0x8D, (byte) 0x4D, (byte) 0x4C, (byte) 0x8C,
                (byte) 0x44, (byte) 0x84, (byte) 0x85, (byte) 0x45, (byte) 0x87, (byte) 0x47, (byte) 0x46, (byte) 0x86, (byte) 0x82, (byte) 0x42, (byte) 0x43, (byte) 0x83, (byte) 0x41, (byte) 0x81, (byte) 0x80, (byte) 0x40
        };

        int crc = 0x0000ffff;
        int ucCRCHi = 0x00ff;
        int ucCRCLo = 0x00ff;
        int iIndex;
        for (int i = 0; i < data.length; ++i) {
            iIndex = (ucCRCLo ^ data[i]) & 0x00ff;
            ucCRCLo = ucCRCHi ^ crc16_h[iIndex];
            ucCRCHi = crc16_l[iIndex];
        }

        crc = ((ucCRCHi & 0x00ff) << 8) | (ucCRCLo & 0x00ff) & 0xffff;
        //高低位互换，输出符合相关工具对Modbus CRC16的运算
        crc = ( (crc & 0xFF00) >> 8) | ( (crc & 0x00FF ) << 8);
        return String.format("%04X", crc);
    }

    public static String getCRC2(byte[] bytes) {
//        ModBus 通信协议的 CRC ( 冗余循环校验码含2个字节, 即 16 位二进制数。
//        CRC 码由发送设备计算, 放置于所发送信息帧的尾部。
//        接收信息设备再重新计算所接收信息 (除 CRC 之外的部分）的 CRC,
//        比较计算得到的 CRC 是否与接收到CRC相符, 如果两者不相符, 则认为数据出错。
//
//        1) 预置 1 个 16 位的寄存器为十六进制FFFF(即全为 1) , 称此寄存器为 CRC寄存器。
//        2) 把第一个 8 位二进制数据 (通信信息帧的第一个字节) 与 16 位的 CRC寄存器的低 8 位相异或, 把结果放于 CRC寄存器。
//        3) 把 CRC 寄存器的内容右移一位( 朝低位)用 0 填补最高位, 并检查右移后的移出位。
//        4) 如果移出位为 0, 重复第 3 步 ( 再次右移一位); 如果移出位为 1, CRC 寄存器与多项式A001 ( 1010 0000 0000 0001) 进行异或。
//        5) 重复步骤 3 和步骤 4, 直到右移 8 次,这样整个8位数据全部进行了处理。
//        6) 重复步骤 2 到步骤 5, 进行通信信息帧下一个字节的处理。
//        7) 将该通信信息帧所有字节按上述步骤计算完成后,得到的16位CRC寄存器的高、低字节进行交换。
//        8) 最后得到的 CRC寄存器内容即为 CRC码。

        int CRC = 0x0000ffff;
        int POLYNOMIAL = 0x0000a001;

        int i, j;
        for (i = 0; i < bytes.length; i++) {
            CRC ^= (int) bytes[i];
            for (j = 0; j < 8; j++) {
                if ((CRC & 0x00000001) == 1) {
                    CRC >>= 1;
                    CRC ^= POLYNOMIAL;
                } else {
                    CRC >>= 1;
                }
            }
        }
        //高低位转换，看情况使用（譬如本人这次对led彩屏的通讯开发就规定校验码高位在前低位在后，也就不需要转换高低位)
        CRC = ( (CRC & 0x0000FF00) >> 8) | ( (CRC & 0x000000FF ) << 8);
        return Integer.toHexString(CRC);
    }

    static byte[] crc8_tab = { (byte) 0, (byte) 94, (byte) 188, (byte) 226, (byte) 97, (byte) 63, (byte) 221, (byte) 131, (byte) 194, (byte) 156, (byte) 126, (byte) 32, (byte) 163, (byte) 253, (byte) 31, (byte) 65, (byte) 157, (byte) 195, (byte) 33, (byte) 127, (byte) 252, (byte) 162, (byte) 64, (byte) 30, (byte) 95, (byte) 1, (byte) 227, (byte) 189, (byte) 62, (byte) 96, (byte) 130, (byte) 220, (byte) 35, (byte) 125, (byte) 159, (byte) 193, (byte) 66, (byte) 28, (byte) 254, (byte) 160, (byte) 225, (byte) 191, (byte) 93, (byte) 3, (byte) 128, (byte) 222, (byte) 60, (byte) 98, (byte) 190, (byte) 224, (byte) 2, (byte) 92, (byte) 223, (byte) 129, (byte) 99, (byte) 61, (byte) 124, (byte) 34, (byte) 192, (byte) 158, (byte) 29, (byte) 67, (byte) 161, (byte) 255, (byte) 70, (byte) 24,
            (byte) 250, (byte) 164, (byte) 39, (byte) 121, (byte) 155, (byte) 197, (byte) 132, (byte) 218, (byte) 56, (byte) 102, (byte) 229, (byte) 187, (byte) 89, (byte) 7, (byte) 219, (byte) 133, (byte) 103, (byte) 57, (byte) 186, (byte) 228, (byte) 6, (byte) 88, (byte) 25, (byte) 71, (byte) 165, (byte) 251, (byte) 120, (byte) 38, (byte) 196, (byte) 154, (byte) 101, (byte) 59, (byte) 217, (byte) 135, (byte) 4, (byte) 90, (byte) 184, (byte) 230, (byte) 167, (byte) 249, (byte) 27, (byte) 69, (byte) 198, (byte) 152, (byte) 122, (byte) 36, (byte) 248, (byte) 166, (byte) 68, (byte) 26, (byte) 153, (byte) 199, (byte) 37, (byte) 123, (byte) 58, (byte) 100, (byte) 134, (byte) 216, (byte) 91, (byte) 5, (byte) 231, (byte) 185, (byte) 140, (byte) 210, (byte) 48, (byte) 110, (byte) 237,
            (byte) 179, (byte) 81, (byte) 15, (byte) 78, (byte) 16, (byte) 242, (byte) 172, (byte) 47, (byte) 113, (byte) 147, (byte) 205, (byte) 17, (byte) 79, (byte) 173, (byte) 243, (byte) 112, (byte) 46, (byte) 204, (byte) 146, (byte) 211, (byte) 141, (byte) 111, (byte) 49, (byte) 178, (byte) 236, (byte) 14, (byte) 80, (byte) 175, (byte) 241, (byte) 19, (byte) 77, (byte) 206, (byte) 144, (byte) 114, (byte) 44, (byte) 109, (byte) 51, (byte) 209, (byte) 143, (byte) 12, (byte) 82, (byte) 176, (byte) 238, (byte) 50, (byte) 108, (byte) 142, (byte) 208, (byte) 83, (byte) 13, (byte) 239, (byte) 177, (byte) 240, (byte) 174, (byte) 76, (byte) 18, (byte) 145, (byte) 207, (byte) 45, (byte) 115, (byte) 202, (byte) 148, (byte) 118, (byte) 40, (byte) 171, (byte) 245, (byte) 23, (byte) 73, (byte) 8,
            (byte) 86, (byte) 180, (byte) 234, (byte) 105, (byte) 55, (byte) 213, (byte) 139, (byte) 87, (byte) 9, (byte) 235, (byte) 181, (byte) 54, (byte) 104, (byte) 138, (byte) 212, (byte) 149, (byte) 203, (byte) 41, (byte) 119, (byte) 244, (byte) 170, (byte) 72, (byte) 22, (byte) 233, (byte) 183, (byte) 85, (byte) 11, (byte) 136, (byte) 214, (byte) 52, (byte) 106, (byte) 43, (byte) 117, (byte) 151, (byte) 201, (byte) 74, (byte) 20, (byte) 246, (byte) 168, (byte) 116, (byte) 42, (byte) 200, (byte) 150, (byte) 21, (byte) 75, (byte) 169, (byte) 247, (byte) 182, (byte) 232, (byte) 10, (byte) 84, (byte) 215, (byte) 137, (byte) 107, 53 };

    /**
     * 計算陣列的CRC8校驗值
     *
     * @param data
     *            需要計算的陣列
     * @return CRC8校驗值
     */
    public static byte calcCrc8(byte[] data) {
        return calcCrc8(data, 0, data.length, (byte) 0);
    }

    /**
     * 計算CRC8校驗值
     *
     * @param data
     *            資料
     * @param offset
     *            起始位置
     * @param len
     *            長度
     * @return 校驗值
     */
    public static byte calcCrc8(byte[] data, int offset, int len) {
        return calcCrc8(data, offset, len, (byte) 0);
    }

    /**
     * 計算CRC8校驗值
     *
     * @param data
     *            資料
     * @param offset
     *            起始位置
     * @param len
     *            長度
     * @param preval
     *            之前的校驗值
     * @return 校驗值
     */
    public static byte calcCrc8(byte[] data, int offset, int len, byte preval) {
        byte ret = preval;
        for (int i = offset; i < (offset + len); ++i) {
            ret = crc8_tab[(0x00ff & (ret ^ data[i]))];
        }
        return ret;
    }

    /**
     * 和校验
     *
     * @param data 校验源，byte数组
     * @param from 校验开始字节序号
     * @param num  校验字节数
     * @return 返回和
     */
    public static byte[] checkSum2Bytes(byte[] data, int from, int num) {
        int sum = 0;
        for (int i = from; i < from + num; i++) {
            sum += Unsignd(data[i]);
        }

        return short2HighLow(sum);
    }

    public static int convertToUnsignedInt(byte high, byte low) {
        int unsignedHigh = high & 0xFF;
        int unsignedLow = high & 0xFF;

        int unsignedInt = (unsignedHigh << 8) | unsignedLow;
        return unsignedInt;
    }

}
